use build_builder::Builder;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};

#[derive(Clone, Debug, Serialize, Builder)]
pub struct BindAccountReq {
    r#type: BindType,
    biz_id: String,
    delivery_id: String,
    password: Option<String>,
    remark_content: Option<String>,
}

#[derive(Clone, Debug, Serialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum BindType {
    #[default]
    Bind,
    Unbind,
}

#[derive(Clone, Debug, Deserialize)]
pub struct BindAccountRes;

#[derive(Clone, Debug, Deserialize)]
pub struct AllAccountRes {
    pub count: u32,
    pub list: Vec<Account>,
}

#[derive(Clone, Debug, Deserialize)]
pub struct Account {
    pub biz_id: String,
    pub delivery_id: String,
    pub create_time: u32,
    pub update_time: u32,
    pub status_code: u32,
    pub alias: String,
    pub remark_wrong_msg: String,
    pub remark_content: String,
    pub quota_num: u32,
    pub quota_update_time: u32,
    pub service_type: Vec<ServiceType>,
}

#[derive(Clone, Debug, Deserialize)]
pub struct ServiceType {
    pub service_type: u32,
    pub service_name: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct AllDeliveryRes {
    pub count: u32,
    pub data: Delivery,
}

#[derive(Clone, Debug, Deserialize)]
pub struct Delivery {
    pub delivery_id: String,
    pub delivery_name: String,
    pub can_use_cash: u32,
    pub can_get_quota: u32,
    pub service_type: ServiceType,
    pub cash_biz_id: String,
}

#[derive(Clone, Debug, Serialize)]
pub struct OrderReq {
    openid: String,
    delivery_id: Option<String>,
    waybill_id: Option<String>,
    order_id: Option<String>,
}

#[derive(Clone, Debug, Serialize, Default)]
pub struct OrderReqBuilder {
    openid: String,
    delivery_id: Option<String>,
    waybill_id: Option<String>,
    order_id: Option<String>,
}

impl OrderReq {
    pub fn builder() -> OrderReqBuilder {
        OrderReqBuilder::default()
    }
}

impl OrderReqBuilder {
    pub fn openid<T>(mut self, openid: T) -> Self
    where
        T: AsRef<str>,
    {
        self.openid = openid.as_ref().to_owned();
        self
    }

    pub fn delivery_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.delivery_id = Some(id.as_ref().to_owned());
        self
    }

    pub fn waybill_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.waybill_id = Some(id.as_ref().to_owned());
        self
    }

    pub fn order_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.waybill_id = Some(id.as_ref().to_owned());
        self
    }

    pub fn build(self) -> OrderReq {
        OrderReq {
            openid: self.openid,
            delivery_id: self.delivery_id,
            waybill_id: self.waybill_id,
            order_id: self.order_id,
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct OrderRes {
    pub delivery_resultcode: u32,
    pub delivery_resultmsg: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct UpdatePrinterRes;

#[derive(Clone, Debug, Serialize)]
pub struct UpdatePrinterReq {
    openid: String,
    update_type: BindType,
    tagid_list: Option<String>,
}

impl UpdatePrinterReq {
    pub fn new<T>(openid: T, update_type: BindType, list: Option<T>) -> Self
    where
        T: AsRef<str>,
    {
        Self {
            openid: openid.as_ref().to_owned(),
            update_type,
            tagid_list: list.map(|l| l.as_ref().to_owned()),
        }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct QuotaReq {
    delivery_id: String,
    biz_id: String,
}

impl QuotaReq {
    pub fn new<T>(delivery_id: T, biz_id: T) -> Self
    where
        T: AsRef<str>,
    {
        Self {
            delivery_id: delivery_id.as_ref().to_owned(),
            biz_id: biz_id.as_ref().to_owned(),
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct QuotaRes {
    pub quota_num: u32,
}

#[derive(Clone, Debug, Serialize, Default)]
pub struct GetOrderReq {
    order_id: String,
    openid: Option<String>,
    delivery_id: String,
    waybill_id: Option<String>,
    print_type: Option<u32>,
    custom_remark: Option<String>,
}

impl GetOrderReq {
    pub fn new<T>(order_id: T, delivery_id: T) -> Self
    where
        T: AsRef<str>,
    {
        Self {
            order_id: order_id.as_ref().to_owned(),
            delivery_id: delivery_id.as_ref().to_owned(),
            ..Default::default()
        }
    }
}

#[derive(Clone, Debug, Serialize, Default)]
pub struct GetOrderReqBuilder {
    order_id: String,
    openid: Option<String>,
    delivery_id: String,
    waybill_id: Option<String>,
    print_type: Option<u32>,
    custom_remark: Option<String>,
}

impl GetOrderReqBuilder {
    pub fn order_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.order_id = id.as_ref().to_owned();
        self
    }

    pub fn delivery_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.delivery_id = id.as_ref().to_owned();
        self
    }

    pub fn openid<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.openid = Some(id.as_ref().to_owned());
        self
    }

    pub fn waybill_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.waybill_id = Some(id.as_ref().to_owned());
        self
    }

    pub fn print_type(mut self, print_type: u32) -> Self {
        self.print_type = Some(print_type);
        self
    }

    pub fn custom_remark<T>(mut self, remark: T) -> Self
    where
        T: AsRef<str>,
    {
        self.custom_remark = Some(remark.as_ref().to_owned());
        self
    }

    pub fn build(self) -> GetOrderReq {
        GetOrderReq {
            order_id: self.order_id,
            openid: self.openid,
            delivery_id: self.delivery_id,
            waybill_id: self.waybill_id,
            print_type: self.print_type,
            custom_remark: self.custom_remark,
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct GetOrderRes {
    pub print_html: String,
    pub order_id: String,
    pub delivery_id: String,
    pub waybill_id: String,
    pub order_status: OrderStatus,
    pub waybill_data: WaybillData,
}

#[derive(Clone, Debug, Deserialize)]
pub struct WaybillData {
    pub key: String,
    pub value: String,
}

#[derive(Clone, Debug, Deserialize_repr)]
#[repr(u8)]
pub enum OrderStatus {
    Normal = 0,
    Cancel = 1,
}

#[derive(Clone, Debug, Serialize)]
pub struct TestUpdateOrderReq {
    biz_id: String,
    order_id: String,
    delivery_id: String,
    waybill_id: String,
    action_time: u32,
    action_type: u32,
    action_msg: String,
}

impl TestUpdateOrderReq {
    pub fn builder() -> TestUpdateOrderReqBuilder {
        TestUpdateOrderReqBuilder::default()
    }
}

#[derive(Clone, Debug, Serialize, Default)]
pub struct TestUpdateOrderReqBuilder {
    biz_id: String,
    order_id: String,
    delivery_id: String,
    waybill_id: String,
    action_time: u32,
    action_type: u32,
    action_msg: String,
}

impl TestUpdateOrderReqBuilder {
    pub fn biz_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.biz_id = id.as_ref().to_owned();
        self
    }

    pub fn order_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.order_id = id.as_ref().to_owned();
        self
    }

    pub fn delivery_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.delivery_id = id.as_ref().to_owned();
        self
    }

    pub fn waybill_id<T>(mut self, id: T) -> Self
    where
        T: AsRef<str>,
    {
        self.waybill_id = id.as_ref().to_owned();
        self
    }

    pub fn action_time(mut self, time: u32) -> Self {
        self.action_time = time;
        self
    }

    pub fn action_type(mut self, action_type: u32) -> Self {
        self.action_type = action_type;
        self
    }

    pub fn action_msg<T>(mut self, msg: T) -> Self
    where
        T: AsRef<str>,
    {
        self.action_msg = msg.as_ref().to_owned();
        self
    }

    pub fn build(self) -> TestUpdateOrderReq {
        TestUpdateOrderReq {
            biz_id: self.biz_id,
            order_id: self.order_id,
            delivery_id: self.delivery_id,
            waybill_id: self.waybill_id,
            action_time: self.action_time,
            action_type: self.action_type,
            action_msg: self.action_msg,
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct TestUpdateOrderRes;

#[derive(Clone, Debug, Deserialize)]
pub struct Printer {
    pub count: u32,
    pub openid: Vec<String>,
    pub tagid_list: Vec<String>,
}

#[derive(Clone, Debug, Serialize)]
pub struct OrderPathReq {
    openid: Option<String>,
    delivery_id: String,
    waybill_id: String,
}

impl OrderPathReq {
    pub fn new<T, U, S>(delivery_id: T, waybill_id: U, openid: Option<S>) -> Self
    where
        T: AsRef<str>,
        U: AsRef<str>,
        S: AsRef<str>,
    {
        Self {
            openid: openid.map(|o| o.as_ref().to_owned()),
            delivery_id: delivery_id.as_ref().to_owned(),
            waybill_id: waybill_id.as_ref().to_owned(),
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct OrderPathRes {
    pub openid: String,
    pub delivery_id: String,
    pub waybill_id: String,
    pub path_item_num: u32,
    pub path_item_list: Vec<PathItem>,
}

#[derive(Clone, Debug, Deserialize)]
pub struct PathItem {
    pub action_time: u32,
    pub action_type: u32,
    pub action_msg: String,
}

#[derive(Clone, Debug, Serialize)]
pub struct BatchGetOrderReq {
    order_list: Vec<OrderItem>,
}

impl BatchGetOrderReq {
    pub fn new(list: &[OrderItem]) -> Self {
        Self {
            order_list: list.to_owned(),
        }
    }
}

#[derive(Clone, Debug, Serialize)]
pub struct OrderItem {
    order_id: String,
    delivery_id: String,
    waybill_id: Option<String>,
}

impl OrderItem {
    pub fn new<T, U, S>(order_id: T, deliver_id: U, waybill_id: Option<S>) -> Self
    where
        T: AsRef<str>,
        U: AsRef<str>,
        S: AsRef<str>,
    {
        Self {
            order_id: order_id.as_ref().to_owned(),
            delivery_id: deliver_id.as_ref().to_owned(),
            waybill_id: waybill_id.map(|w| w.as_ref().to_owned()),
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct BatchGetOrderRes {
    pub order_list: Vec<BatchOrderItem>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct BatchOrderItem {
    pub errcode: u32,
    pub errmsg: String,
    pub print_html: String,
    pub order_id: String,
    pub delivery_id: String,
    pub waybill_id: String,
    pub order_status: OrderStatus,
    pub waybill_data: WaybillData,
}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct AddOrderReq {
    order_id: String,
    openid: String,
    delivery_id: String,
    biz_id: String,
    custom_remark: Option<String>,
    tagid: Option<u32>,
    add_source: u32,
    wx_appid: Option<String>,
    expect_time: Option<u32>,
    take_mode: Option<u32>,
    sender: Sender,
    receiver: Receiver,
    cargo: Cargo,
    shop: Shop,
    insured: Insured,
    service: Service,
}

#[derive(Clone, Debug, Serialize, Deserialize, Builder)]
pub struct Sender {
    name: String,
    tel: String,
    mobile: String,
    company: String,
    post_code: String,
    country: String,
    provice: String,
    city: String,
    area: String,
    address: String,
}

#[derive(Clone, Debug, Serialize, Deserialize, Builder)]
pub struct Receiver {
    name: String,
    tel: String,
    mobile: String,
    company: String,
    post_code: String,
    country: String,
    provice: String,
    city: String,
    area: String,
    address: String,
}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct Cargo {
    count: u32,
    weight: u32,
    space_x: u32,
    space_y: u32,
    space_z: u32,
}

#[derive(Clone, Debug, Serialize)]
pub struct Shop {
    wxa_path: Option<String>,
    img_url: Option<String>,
    goods_name: Option<String>,
    goods_count: Option<u32>,
    // TODO: 更新detail_list
    detail_list: Vec<String>,
}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct Insured {
    use_insured: UseInsured,
    insured_value: Option<u32>,
}

#[derive(Clone, Debug, Serialize_repr)]
#[repr(u8)]
pub enum UseInsured {
    No = 0,
    Yes = 1,
}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct Service {
    service_type: u32,
    service_name: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct AddOrderRes {
    pub order_id: String,
    pub waybill_id: String,
    pub delivery_resultcode: u32,
    pub delivery_resultmsg: String,
    pub waybill_data: Vec<WaybillData>,
}

#[derive(Clone, Debug, Serialize)]
pub struct UpdateBusinessReq {
    shop_app_id: String,
    biz_id: String,
    result_code: u32,
    result_msg: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct UpdateBusinessRes {}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct UpdatePathReq {
    token: String,
    waybill_id: String,
    action_time: u32,
    action_type: u32,
    action_msg: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct UpdatePathRes {}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct PreviewTemplateReq {
    waybill_id: String,
    waybill_template: String,
    waybill_data: String,
    custom: CustomTemplate,
}

#[derive(Clone, Debug, Serialize, Builder)]
pub struct CustomTemplate {
    order_id: String,
    openid: String,
    delivery_id: String,
    biz_id: String,
    custom_remark: Option<String>,
    tagid: Option<u32>,
    add_source: u32,
    wx_appid: Option<String>,
    sender: Sender,
    receiver: Receiver,
    cargo: Cargo,
    shop: Shop,
    insured: Insured,
    service: Service,
    expect_time: Option<u32>,
    take_mode: Option<u32>,
}

#[derive(Clone, Debug, Deserialize)]
pub struct PreviewTemplateRes {
    pub waybill_id: String,
    pub rendered_waybill_template: String,
}

#[derive(Clone, Debug, Serialize)]
pub struct ContractReq {
    token: String,
    waybill_id: String,
}

impl ContractReq {
    pub fn new<T, U>(token: T, waybill_id: U) -> Self
    where
        T: AsRef<str>,
        U: AsRef<str>,
    {
        Self {
            token: token.as_ref().to_owned(),
            waybill_id: waybill_id.as_ref().to_owned(),
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct ContractRes {
    pub waybill_id: String,
    pub sender: Sender,
    pub receiver: Receiver,
}
